#ifndef GAMECORE_H
#define GAMECORE_H

#include "Player.h"

#include "../Game/GameDefine.h"
#include "../Game/SocketDefine.h"

#include <QThread>

class TcpSocket;

//点击牌返回的参数
//如果点击类型是Wujiang,则nPlayerID是武将ID,否则是所在类型下标
struct DianJiPai
{
public:
    //0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096
    int         iID;       //对象ID
    _BaseObject::_Area  nType;            //牌 类型(手牌/人/武器/防具/马/判定区)
    int         nFlags;            //牌 状态

    int         nPlayerID;        //牌 所属玩家ID
    int         nValue;            //牌 值
    _BaseObject *pObject;       //指向被点击的对象
public:
    DianJiPai();
};


//选牌的 某个步骤
struct PokeStep
{
public:
    bool        bSelfFlag;        //牌 是否选自己的区域(off)
    bool        bMultipleFlag;    //牌 可以多选
    int         nMaxCount;      //牌 每步要选的最多总数
    int         nMinCount;      //牌 每步要选的最少总数
    _BaseObject::_Areas nType;            //牌 GameSlot类型(手牌/人/武器/防具/马/判定区),可按位叠加

    qint32      nSelectPlayerID;                    //牌 所属对象,无(按钮和敌人)则-1
    qint32      nSelectCount;                        //牌 已选个数
    qint32      nSelectValue[GAME_MAX_NUM_CHOICE];    //牌 选择的值
    _BaseObject::_Area  nSelectType[GAME_MAX_NUM_CHOICE];    //牌 类型(手牌/人/武器/防具/马/判定区)
//    char        strMsg[GAME_MAX_NUM_MSG];            //选牌时显示的信息
public:
    PokeStep();
};


class GameCore: public QThread
{
    Q_OBJECT
    Q_ENUMS(_GameStatus)

    Q_ENUMS(_GameButtonValue)
    Q_ENUMS(_GameShenFen)


    Q_PROPERTY(_GameStatus gameStatus READ gameStatus)

    Q_PROPERTY(QObjectList pokeList READ pokeList)
    Q_PROPERTY(QObjectList playerList READ playerList)
    Q_PROPERTY(QObjectList wuJiangList READ wuJiangList)

    Q_PROPERTY(bool isWin READ isWin)   //是否获胜
    Q_PROPERTY(bool isTerminateGame READ isTerminateGame)//玩家强制结束游戏(扣分显示)


//框架类型
public:
    enum _GameType      //游戏类型
    {
        Game_Type_NULL = 0,
        Game_Type_1,
    };
    enum _GameStatus    //游戏状态
    {
        Game_Status_ERROR = -1,       //游戏出错
        Game_Status_Continue = 0,   //继续游戏
        //Game_Status_NextTurn,
        Game_Status_GameOver,       //游戏正常结束
        Game_Status_Exit,           //网络指令 游戏退出(玩家被动)
        Game_Status_Terminated,     //游戏强制退出(玩家主动)
    };

//游戏类型
public:
    //按钮值
    enum _GameButtonValue
    {
        Game_Button_ERROR = -1,
        Game_Button_OK = 0,
        Game_Button_Cancel = 1,
        Game_Button_Giveup = 2,
        //Game_Button_JiNeng = 10,
    };
    enum _GameShenFen   //身份,暂时不用!
    {
        Game_ShenFen_NULL,
        Game_ShenFen_1,
        Game_ShenFen_2,
        Game_ShenFen_3,
        Game_ShenFen_4,
    };

    //出牌函数的类型参数(阶段)
    enum _GameChuPaiType
    {
        Game_ChuPai_Type_ZhuDong = 0,   //出牌阶段(牌,武器,技能牌)
        Game_ChuPai_Type_Pai,           //需要什么牌或技能牌
        Game_ChuPai_Type_JiNeng,        //某技能发动
        Game_ChuPai_Type_QiPai,         //弃牌
    };

public:
    explicit GameCore(QObject *parent = nullptr);
    virtual ~GameCore() Q_DECL_OVERRIDE;



//框架信号
signals:
    //void s_FlagMenus2(QVariant ok, QVariant cancel, QVariant giveup);      //设置按钮状态
    //void s_FlagMenus1(_BaseObject::_Flags ok, _BaseObject::_Flags cancel, _BaseObject::_Flags giveup);      //设置按钮状态
    void s_InitOnce(int nPokeMaxCount,int nPlayerMaxCount);     //给qml通知
    void s_GameInitFinished(int playerCount,int myID);          //游戏初始化
    void s_GameBegin();                                         //游戏开始
    void s_GameOver(_GameStatus nRet);                          //游戏结束时通知

//给外部发送的信息:
    //void s_RefreshUI();                           //刷新UI
    void s_Message(QString msg);                    //游戏中显示信息
    void s_Debug(QString msg);                      //显示调试信息
    void s_Critical(QString msg);                   //显示错误信息


//游戏信号,本类发出
signals:
    void s_FlagMenus(int ok, int cancel, int giveup);       //设置按钮状态
    void s_ChoiceWuJiang();                                 //选择武将

    //void s_ShowShortMessage(QString);                 //显示短消息
    void s_ShowChuPaiMessage(QString msg);              //显示短消息
    //void s_ShowWenTiMessage(QString msg);             //显示短消息

    void s_RefreshAllPokePosition();                    //刷新所有牌的位置
    void s_RefreshAllFlags();                           //刷新所有元素的flags


    //显示问题框;
    //type:=1,用户选择;=3,其他人;=2:电脑选择;=0:显示选择答案
    void s_Wenti(QObject *wenti, int type, int time);
    void s_ShowPlayersArea(int player);         //player为-1则隐藏


    void s_StartChuPai(int player);                  //某个player准备选牌时发送
    void s_StopChuPai(int player);                   //某个player一次选牌完毕时

    void s_ChuPaiOver(QVariantList list);       //出牌结束后的划线






//框架函数:

public:
    virtual int InitOnce();         //进行初始化(仅1次,由外部配置好后调用)
    virtual int InitOnceInThread(); //线程中初始化(1次)

    //每次游戏开始前初始化,sr为随机数种子
    virtual int GameInit(int sr = -1);

    //游戏开始调用
    virtual _GameStatus GameBegin();

    //游戏结束
    virtual int GameOver();

    //强制结束游戏,尽量调用后加wait()
    virtual void TerminateGame(int ret, _GameStatus status = Game_Status_Exit)
    {
        setGameStatus(status);
        qDebug() << "TerminateGame:" << ret;
    }

protected:
    //检测游戏是否结束,返回Game_Status_Continue或Game_Status_Gameover
    virtual _GameStatus CheckGameOver();

    //设置游戏状态
    virtual _GameStatus setGameStatus(_GameStatus status);

private:




//框架(其他)

public:

    //virtual void Sleep(unsigned long msec){msleep(msec);}

public slots:
    //virtual void questionFinished(int answerChoice = -1){}
    virtual void sl_UserActionFinished(){}
    //virtual void netFinished(){}

protected:
//UI游戏框架
    virtual void WaitForUserAction();
    //virtual void WaitForNet(){}
    //virtual void WaitForQuestion(){}
    //virtual _GameData *WaitingForOthers() = 0;








//英语杀

protected:
    //选择武将(count为玩家数)
    virtual _GameStatus ChoiceWuJiang(int count);

    //洗牌ok
    //将qipaidui随机放入paidui中,将所有qipaidui的leixing置为 -1,
    virtual bool Xipai();
        bool CreatePaiDuiID();  //产生 QiPaiDuiShu个随机数 到 m_arrayPaiDuiID
        void RefreshPaiDui();   //根据 m_arrayPaiDuiID 随机将QiPaiDui依次放入PaiDui

    //晒点,返回0~5
    virtual int ShaiDian();

    //问英语,答案错误返回false
    virtual bool WenTi(int player, QString msg, int time)
    {
        return true;
    }
    //显示和隐藏某一玩家的牌区
    virtual int ShowPlayersArea(int player) = 0;
    virtual int HidePlayersArea() = 0;


    //游戏中显示的名字
    QString getPlayerShowName(int player)
    {
        QString name = _T("<font size=3 color=#FF6060>%1</font>");
        if(player < 0 || player >= GAME_MAX_NUM_PLAYER)
            return name.arg("[!ERROR]超出范围的武将!");

        if(m_arrayPlayer[player].isMe())
            //return name.arg(m_arrayPlayer[player].m_strName);
            return name.arg(m_arrayPlayer[player].getWujiangData()->getName());
            //return name.arg("您");
        else if(m_arrayPlayer[player].isComputer())
            return name.arg(m_arrayPlayer[player].getWujiangData()->getName());
        else if(m_arrayPlayer[player].isOtherPlayer())
            return name.arg(m_arrayPlayer[player].getWujiangData()->getName());
            //return name.arg(m_arrayPlayer[player].m_strName);
        else
            return name.arg("[!ERROR]未知玩家");
    }


//点击函数
    void _ClickButton_(int button)
    {
        m_DianJiPai.nPlayerID = -1;
        m_DianJiPai.nType = _BaseObject::Area_Button;
        m_DianJiPai.nValue = button;
        m_DianJiPai.nFlags = m_flagsButton[button];
        m_DianJiPai.pObject = nullptr;
    }

    void _ClickPai_(_Pai* p)
    {
        m_DianJiPai.nPlayerID = p->positionPlayer();
        m_DianJiPai.nType = p->positionArea();
        m_DianJiPai.nValue = p->positionValue();
        m_DianJiPai.nFlags = p->flags();
        m_DianJiPai.pObject = p;
    }

    void _ClickPlayer_(int n)
    {
        m_DianJiPai.nPlayerID = n;
        m_DianJiPai.nType = _BaseObject::Area_Player;
        m_DianJiPai.nValue = n;
        m_DianJiPai.nFlags = m_arrayPlayer[n].flags();
        m_DianJiPai.pObject = m_arrayPlayer + n;
    }

    void _ClickJiNeng_(_Pai* pJiNeng)
    {
        m_DianJiPai.nPlayerID = pJiNeng->positionPlayer();
        m_DianJiPai.nType = pJiNeng->positionArea();
        m_DianJiPai.nValue = pJiNeng->positionValue();
        m_DianJiPai.nFlags = pJiNeng->flags();
        m_DianJiPai.pObject = pJiNeng;
    }


private:
    //摸牌ok
    //牌堆;牌堆剩余牌数;弃牌堆;弃牌堆数
    //摸一张牌,然后返回此牌;出错返回NULL
    _Pai* Mo1Pai();
    //把p放入弃牌堆,返回弃牌堆数目
    int QiPai(_Pai *p);

    //返回 GAMEOVER 游戏结束;0 正常返回
    //player的回合
    //virtual int Huihe(int player);


    void InitJiNeng(int player);

    _GameStatus HuiHeKaiShi(int player);
    _GameStatus PanDingJieDuan(int player);
    _GameStatus MoPaiJieDuan(int player);
    _GameStatus ChuPaiJieDuan(int player);
    _GameStatus QiPaiJieDuan(int player);
    _GameStatus HuiHeJieShu(int player);



    _GameStatus HuiHeKaiShiChuLi(int player);
    _GameStatus PanDingChuLi(int player);
    _GameStatus MoPaiChuLi(int player);
    _GameStatus ChuPaiChuLi(int player);
    _GameStatus QiPaiChuLi(int player);
    _GameStatus HuiHeJieShuChuLi(int player);



    //摸n张牌放入shoupai中,多余的放在弃牌堆
    bool MoPai(int player,int n);

    //计算player1和player2距离,type=0计算本身距离是否够着;type=1计算距离(包含马);type=2计算杀距离(包含武器和马),注意死亡玩家
    bool ComputeDistent(int player1,int player2,int type);

    //得到player的下一个未死玩家
    int GetNextPlayer(int player);

//死亡处理
    //player掉血n,player1是伤害源(-1为无)
    //如果体力>0或求桃成功,则Game_Status_Continue
    //如果死亡并游戏结束,返回GAMEOVER
    _GameStatus DiaoXue(int n, int player, int player1 = -1, _Pai::_PaiValue v = _Pai::Value_Null);
        //player1向player2求桃
        //有桃返回 Game_Button_OK,否则返回 Game_Button_Cancel
        _GameButtonValue QiuTao(int player1,int player2);

        //设置某人死亡并弃牌,返回游戏是否结束,
        _GameStatus SetPlayerDead(int player);





//牌效果
    //player杀player1
    _GameStatus Sha(int player, int player1, bool bAllowShan = true, _GameChuPaiType type = Game_ChuPai_Type_ZhuDong);

    //player出闪,出杀(m_strMsg保存 是否出杀的字符串)
    _GameButtonValue ChuShan(int player, int count = 1, QString msg = "");
    _GameButtonValue ChuSha(int player, int min = 1, int max = 1, QVariant param = -1, QString msg = "");

    //player吃【桃】,返回体力值
    int ChiTao(int player);

    _GameStatus Chai(int player, int player1);
    _GameStatus Shun(int player, int player1);
    _GameStatus WuZhong(int player);
    _GameStatus JieDao(int player, int player1, int player2);
    _GameStatus WanJian(int player);
    _GameStatus NanMan(int player);
    bool GaoKao(int player, int player1);
    int ShanDian(int player, _Pai* p);
    int Le(int player, int player1, _Pai* p);

    _GameStatus ZhuangBeiWuQi(int player);


    //牌效果完毕后,进行弃牌处理,并进行划线保存,发送给QML
    //type:为1时显示画线,否则不画
    //返回Game_Status_Continue or Game_Status_Gameover
    _GameStatus XiaoGuoQiPai(int type = 1);


//技能效果
    _GameStatus DiaoXueJiNeng(int n, int player, int player1, _Pai::_PaiValue v);
    _GameStatus HuiHeKaiShiJiNeng(int player);
    _GameStatus HuiHeJieShuJiNeng(int player);
    _GameStatus ChuShanJiNeng(int player, int player1);



    //玩家player是否在场并存活
    //bAll表示是否 开启 all标记(如果bAll为true,则player<0时返回true,反之为false)
        //也就是说,关闭bAll时,player必须提供一个具体值(比如EnableAllPlayersByDistent)
    bool CheckPlayerPlay(int player, bool bAll)
    {
        if(player >= GAME_MAX_NUM_PLAYER)return false;
        else if(player >= 0)
        {
            if(m_arrayPlayer[player].dead() == true || m_arrayPlayer[player].m_bUsing == false)
                return false;
        }
        else    //<0,全部武将
        {
            if(!bAll)   //是否可以 全部武将
                return false;
        }
        return true;
    }


//电脑AI:
    //player为-1,则初始化一下
    _GameButtonValue ComputerChuPai(int player, int nStep, int canChoiceCount, _GameChuPaiType eType, int nValue, int nParam1, int nParam2, QVariant nParam3);
    int ComputerQiPai(int player,int min,int max);



//设置状态函数集合:
    //设置按钮bEnable(0/1)
    void FlagMenus(_BaseObject::_Flags ok, _BaseObject::_Flags cancel, _BaseObject::_Flags giveup);

    //除player的武将 全部置为Flag_NULL(包括本身,所有所属牌)
    int ResetAllPlayers(int player = -1);

    //将所有武将 等于/设置/取消 flags
    //type表示eFlags赋值方式(等于,设置,清除)
    //player = -1 表示所有,为0以上则除player外全部
    //返回可点个数
    int FlagAllPlayers(_BaseObject::_Flags eFlags, _BaseObject::_FlagType type = _BaseObject::FlagType_Set, int player = -1);

    /*
    下面的函数:
        test表示只是统计可点个数,不真正设置enable
        ignoreEnable:为0表示对每个角色都重新设置Enable或取消Enable
            为1表示跳过已经设置为Enable的,但计入个数中
            为2表示跳过没有设置为Enable的,相当于只对标记了Enable的操作
    */



    //根据 所有武将 的 判定牌 个数是否大于0 来 等于/设置/取消 flags
    //type表示eFlags赋值方式(等于,设置,清除)
    //player = -1 表示所有,为0以上则除player外全部
    //返回设置为flags的武将数
    int FlagAllPlayersByPanDing(_BaseObject::_Flags flags, _Pai::_PaiValue pandingValue = _Pai::Value_All, int player = -1, bool test = false, int ignoreEnable = 0);

    //用PaiCount来标记Players,compare(0为等于count,<0为小于,>0为大于)
    int FlagAllPlayersByPaiCount(_BaseObject::_Flags flags, int compareType, int count = 0, int player = -1, bool test = false, int ignoreEnable = 0);

    //设置所有武将的装备(按areas设置)
    int FlagAllPlayersWeapon(_BaseObject::_Flags eFlags, _BaseObject::_Areas areas = _BaseObject::Area_ZhuangBei, _BaseObject::_FlagType type = _BaseObject::FlagType_Set, int player = -1);

    //根据player的距离设置武将
    //type=1计算距离(包括马),type=2计算杀距离(包括武器和马)
    //返回可点个数,-1为错误
    int EnableAllPlayersByDistent(int player,int type, bool test = false, int ignoreEnable = 0);

    //根据装备设置武将
    //player为 -1 时全部武将,为具体值时不包括player; weapon=_Pai::Value_All 时全部,为具体时只是这个具体值;
    //返回可点个数,-1错误
    //int TestAllPlayersByWeapon(int player, int weaponValue, int ignoreEnable = 0);
    int EnableAllPlayersByZhuangBei(int player = -1, _Pai::_PaiValue value = _Pai::Value_All, bool test = false, int ignoreEnable = 0);
    int EnableAllPlayersByPanDing(int player = -1, _Pai::_PaiValue value = _Pai::Value_All, bool test = false, int ignoreEnable = 0);

    //手牌>0
    //int TestAllPlayersByShouPai(int player, int ignoreEnable = 0);
    int EnableAllPlayersByShouPai(int player = -1, bool test = false, int ignoreEnable = 0);



//出牌函数
protected:
    //出牌函数:
    //出牌阶段
    //nType:出牌的类型;0:主动出牌(nValue为0）;1:被动出牌(nValue牌值,nParam1/2/3参数);2:弃牌(nValue牌数)
    //返回OK,CANCEL,GIVEUP
    //nParam1/2/3:额外参数,比如寒冰箭的被发动者,桃的被救者
    virtual _GameButtonValue ChuPai(int player, _GameChuPaiType eType, int nValue, int nParam1 = -1, int nParam2 = -1, QVariant nParam3 = -1, int nInitStep = 0, QString strMsg = "");
    //根据nType,初始化第nStep个步骤,返回可点击牌数目
    int InitChuPaiStatus(int player, _GameChuPaiType eType, int nValue, int nParam1, int nParam2, QVariant nParam3, int nStep, QString strMsg);
    int ResetAllFlagsByStep(int nStep); //将已点选的所有元素,重新按照step设置Flags

    //eType分为主动被动,区别在于 弃牌 按钮 显隐
    int ChuPai_ZhangBa(int player, _GameChuPaiType eType, int nStep);
    int ChuPai_TanSu(int player, _GameChuPaiType eType, int nStep);



//
    void startChuPai(int player)
    {
        emit s_StartChuPai(player);
    }

    void stopChuPai(int player)
    {
        emit s_StopChuPai(player);
    }

    virtual void ShowChuPaiMessage(QString str, unsigned long delay = 0)
    {
        emit s_ShowChuPaiMessage(str);

        if(delay > 0)
            msleep(delay);
    }
/*
    void ShowWenTiMessage(QString str)
    {
        //emit s_ShowWenTiMessage(str);
    }*/


//槽
public slots:




//框架属性:
public:
    _GameStatus gameStatus() const
    {
        return m_eGameStatus;
    }


//游戏属性
public:

    QObjectList pokeList() const
    {
        return m_listPaiDui;
    }
    QObjectList playerList() const
    {
        return m_listPlayer;
    }
    QObjectList wuJiangList() const
    {
        return m_listWuJiang;
    }

    virtual bool isWin() const
    {
        return m_nWinner < 0 ? false : m_nWinner == m_arrayPlayer[m_nMyID].m_nDuiWu;
    }
    virtual bool isTerminateGame() const
    {
        return gameStatus() == Game_Status_Terminated;
    }


//重载
protected:
    virtual void run() Q_DECL_OVERRIDE;






//成员数据

//框架数据
private:
    bool m_bInitOnce;   //是否初始化过
    bool m_bInitOnceInThread;   //是否初始化过
public:
    _GameStatus m_eGameStatus;      //游戏状态,结束,继续,强制退出,错误等



public:
//游戏外部设置:
    _GameType   m_eGameType;
    qint32      m_nPlayerCount;    //玩家数
    qint32      m_nMyID;          //本人ID(下标)
    bool        m_bMaster;       //是否房主
    int         m_nGameRandom;   //游戏随机数(局数)
    int         m_nGameMessageDelay;   //游戏信息速度
    //bool        m_bTerminateGame;        //玩家强制结束游戏(扣分显示)

    //QList<_Player::JiaoSe> jiaoSeList;  //所有人的角色


//游戏数据
    _Pai        *m_arrayPai;        //所有原始牌的数组
    _Player     *m_arrayPlayer;      //[GAME_MAX_NUM_PLAYER];        //所有玩家数组
    //_WuJiang    *m_WuJiang;        //武将
    QMap<int,int> m_mapWuJiangUsingTimes;        //武将使用次数

    //3个按钮的值,确定0,取消1,弃牌2,也是下标
    _BaseObject::_Flags        m_flagsButton[3];

    QHash<int,QStringList>   m_hashGameMessage;        //所有提示字符串hash列表


//游戏使用中数据
    //pai yuanshipaidui[2][4][13];    //4种花色,13个点数
    _Pai*       m_arrayPaiDui[GAME_MAX_NUM_PAI];        //牌堆的数组指针
    _Pai*       m_arrayQiPaiDui[GAME_MAX_NUM_PAI];     //弃牌堆的数组指针
    qint32      m_nPaiDuiShu;
    qint32      m_nQiPaiDuiShu;

    qint32      m_arrayPaiDuiID[GAME_MAX_NUM_PAI];     //牌堆ID存放顺序(用来网络发送),实际存的比ID大1!


    qint32      m_nGameRound;        //谁的回合
    //_GameShenFen eWinner;        //0:平;1:主公2:忠臣;3:反贼;4:内奸
    qint32      m_nWinner;        //赢家的DuiWu


    //In:
    DianJiPai    m_DianJiPai;                      //点击牌的返回值
    //Out:
    PokeStep    m_arrayStep[GAME_MAX_NUM_STEP];        //出牌步骤
    qint32      m_nStepCount;                      //出牌的步骤数(发送用)
    //QString   shortMsg;                       //出牌消息

    QString     m_strMsg;


protected:
    //QML用
    QObjectList m_listPaiDui;        //所有牌 堆
    QObjectList m_listWuJiang;        //所有武将
    QObjectList m_listPlayer;       //玩家

    //QStringList m_StrList;

};

//Q_DECLARE_METATYPE(GameCore::_GameStatus)

#endif // GAMECORE_H
